package com.benshou.bcss.common.j17common;

import com.benshou.bcss.common.j17common.annotation.NotBlank;
import com.benshou.bcss.common.j17common.annotation.NotEmpty;
import com.benshou.bcss.common.j17common.annotation.NotNull;
import com.benshou.bcss.common.j17common.annotation.Null;
import lombok.NonNull;

import java.util.Collection;
import java.util.Map;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * @author <a href="mailto:wh1zper@qq.com">wh1zper</a>
 */
public class Requires {

    public static <T> T pass(
            T object,
            @NonNull Predicate<? super T> predicate,
            String failMessage) throws IllegalArgumentException {
        if (!predicate.test(object)) {
            throw new IllegalArgumentException(failMessage);
        }

        return object;
    }

    public static <T, E extends Exception> T pass(
            T object,
            @NonNull Predicate<? super T> predicate,
            @NonNull Supplier<@NotNull ? extends E> exceptionSupplier) throws E {
        if (!predicate.test(object)) {
            throw exceptionSupplier.get();
        }

        return object;
    }

    public static boolean isTrue(Boolean expression, String failMessage) throws IllegalArgumentException {
        if (!Boolean.TRUE.equals(expression)) {
            throw new IllegalArgumentException(failMessage);
        }

        return true;
    }

    public static <E extends Exception> boolean isTrue(
            Boolean expression,
            @NonNull Supplier<@NotNull ? extends E> exceptionSupplier) throws E {
        if (!Boolean.TRUE.equals(expression)) {
            throw exceptionSupplier.get();
        }

        return true;
    }

    @NotNull
    public static <T> T notnull(T object, String failMessage) throws IllegalArgumentException {
        if (object == null) {
            throw new IllegalArgumentException(failMessage);
        }

        return object;
    }

    @NotNull
    public static <T, E extends Exception> T notnull(
            T object,
            @NonNull Supplier<@NotNull ? extends E> exceptionSupplier) throws E {
        if (object == null) {
            throw exceptionSupplier.get();
        }

        return object;
    }

    @Null
    public static <T> T isnull(T object, String failMessage) throws IllegalArgumentException {
        if (object != null) {
            throw new IllegalArgumentException(failMessage);
        }

        return null;
    }

    @Null
    public static <T, E extends Exception> T isnull(
            T object,
            @NonNull Supplier<@NotNull ? extends E> exceptionSupplier) throws E {
        if (object != null) {
            throw exceptionSupplier.get();
        }

        return null;
    }

    @NotNull
    @NotEmpty
    public static <T> T[] notEmpty(T[] array, String failMessage) throws IllegalArgumentException {
        if (array == null || array.length == 0) {
            throw new IllegalArgumentException(failMessage);
        }

        return array;
    }

    @NotNull
    @NotEmpty
    public static <T, E extends Exception> T[] notEmpty(
            T[] array,
            @NonNull Supplier<@NotNull ? extends E> exceptionSupplier) throws E {
        if (array == null || array.length == 0) {
            throw exceptionSupplier.get();
        }

        return array;
    }

    @NotNull
    @NotEmpty
    public static <C extends Collection<?>> C notEmpty(
            C collection,
            String failMessage) throws IllegalArgumentException {
        if (collection == null || collection.isEmpty()) {
            throw new IllegalArgumentException(failMessage);
        }

        return collection;
    }

    @NotNull
    @NotEmpty
    public static <C extends Collection<?>, E extends Exception> C notEmpty(
            C collection,
            @NonNull Supplier<@NotNull ? extends E> exceptionSupplier) throws E {
        if (collection == null || collection.isEmpty()) {
            throw exceptionSupplier.get();
        }

        return collection;
    }

    @NotNull
    @NotEmpty
    public static <M extends Map<?, ?>> M notEmpty(M map, String failMessage) throws IllegalArgumentException {
        if (map == null || map.isEmpty()) {
            throw new IllegalArgumentException(failMessage);
        }

        return map;
    }

    @NotNull
    @NotEmpty
    public static <M extends Map<?, ?>, E extends Exception> M notEmpty(
            M map,
            @NonNull Supplier<@NotNull ? extends E> exceptionSupplier) throws E {
        if (map == null || map.isEmpty()) {
            throw exceptionSupplier.get();
        }

        return map;
    }

    @NotNull
    @NotBlank
    public static String notBlank(String string, String failMessage) throws IllegalArgumentException {
        if (string == null || string.isBlank()) {
            throw new IllegalArgumentException(failMessage);
        }

        return string;
    }

    @NotNull
    @NotBlank
    public static <E extends Exception> String notBlank(
            String string,
            @NonNull Supplier<@NotNull ? extends E> exceptionSupplier) throws E {
        if (string == null || string.isBlank()) {
            throw exceptionSupplier.get();
        }

        return string;
    }
}
